package com.zenithmind.library.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

import com.zenithmind.common.config.AuthInterceptorConfig;

import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;

/**
 * 图书管理服务安全配置
 * 遵循单一职责原则：只负责安全配置相关的设置
 * 遵循开闭原则：通过配置类扩展安全规则，而不是修改现有代码
 * 遵循依赖倒置原则：依赖抽象的安全配置接口
 *
 * @author ZenithMind
 * @since 2024-06-14
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class LibrarySecurityConfig {

    private final LibrarySecurityEndpoints securityEndpoints;

    public LibrarySecurityConfig() {
        this.securityEndpoints = new LibrarySecurityEndpoints();
    }

    /**
     * 图书管理服务安全配置
     * 遵循单一职责原则：只负责安全过滤器链的配置
     */
    @Bean
    @Order(1)
    public SecurityFilterChain librarySecurityFilterChain(HttpSecurity http) throws Exception {

        http
            // 禁用CSRF保护
            .csrf(AbstractHttpConfigurer::disable)
            // 配置认证和授权规则
            .authorizeHttpRequests(authorize -> {
                // 明确允许API文档相关端点
                authorize.requestMatchers(securityEndpoints.getAuthWhitelist()).permitAll();
                // 允许公开端点 - 使用统一配置
                authorize.requestMatchers(securityEndpoints.getPublicEndpoints()).permitAll();
                // 管理员角色端点 - 最高权限，优先配置
                authorize.requestMatchers(securityEndpoints.getAdminEndpoints()).hasRole("ADMIN");
                // 图书管理员角色端点
                authorize.requestMatchers(securityEndpoints.getLibrarianEndpoints()).hasAnyRole("LIBRARIAN", "ADMIN");
                // 用户角色端点
                authorize.requestMatchers(securityEndpoints.getUserEndpoints()).authenticated();
                // 其他请求需要认证
                authorize.anyRequest().authenticated();
            })
            // 使用无状态会话
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            // 禁用OAuth2资源服务器功能
            .oauth2ResourceServer(AbstractHttpConfigurer::disable);

        return http.build();
    }

    /**
     * 配置认证拦截器的跳过路径
     * 遵循依赖倒置原则：通过配置类管理依赖关系
     * 使用统一的端点配置，确保Spring Security和认证拦截器使用相同的跳过路径
     */
    @Bean
    public BeanPostProcessor libraryAuthPropertiesPostProcessor() {
        return new LibraryAuthPropertiesPostProcessor(securityEndpoints);
    }

    /**
     * 认证属性后处理器
     * 遵循单一职责原则：只负责认证属性的后处理
     */
    private static class LibraryAuthPropertiesPostProcessor implements BeanPostProcessor {

        private final LibrarySecurityEndpoints securityEndpoints;

        public LibraryAuthPropertiesPostProcessor(LibrarySecurityEndpoints securityEndpoints) {
            this.securityEndpoints = securityEndpoints;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof AuthInterceptorConfig.AuthProperties && "authProperties".equals(beanName)) {
                AuthInterceptorConfig.AuthProperties properties = (AuthInterceptorConfig.AuthProperties) bean;
                String[] allPublicEndpoints = securityEndpoints.getAllPublicEndpoints();
                properties.setSkipPaths(Arrays.asList(allPublicEndpoints));
                log.info("已为图书管理服务认证拦截器设置统一的跳过路径配置，路径数量: {}", allPublicEndpoints.length);
            }
            return bean;
        }
    }
}
